#pragma once
#include<pthread.h>
#include<vector>
#include<queue>
#include<mutex>
#include<string>
#include<unistd.h>
#include"mythread.hpp"
#include"mutex.hpp"
#include"task.hpp"

using namespace std;
template<class T>
class threadPool;

template<class T>
class threadData
{
public:
threadPool<T>* _tpp;//指向threadpool的指针
string tpp_name;//线程名

threadData(threadPool<T>*tpp,const string& tppname )
:_tpp(tpp)
,tpp_name(tppname)
{
    //noting
}
};


 const int gnum=3;
 template<class T>
class threadPool
{
private:

static void* handlertask(void* args)
{
    threadData<T>* tdp=static_cast<threadData<T>*>(args);
    while(true)
    {
    T t;
    {LockReady lr(tdp->_tpp->Mutex());//加锁
    while(tdp->_tpp->isqueueempty())
    {
     tdp->_tpp->condwait();//如果队列为空，则线程需要在条件变量处等待
    }
  t=  tdp->_tpp->pop();//从队列中取数据

    }
    cout<<"threadname: "<<tdp->tpp_name<<"get task: "<<t.taskstringforP()<<"and ret: "<<t()<<endl;
    }

}
    threadPool(const int num=gnum):_num(num)
    {
        pthread_mutex_init(&_mut,nullptr);//互斥量的初始化
        pthread_cond_init(&_cond,nullptr);//条件变量的初始化
        for(int i=0;i<_num;i++)
        {
          _threads.push_back(new thread());//创建新线程对象并放到数组里面
        }
    }

public:

void lockqueue(){pthread_mutex_lock(&_mut);}//加锁
void unlockqueue(){pthread_mutex_unlock(&_mut);}//解锁
void condwait(){pthread_cond_wait(&_cond,&_mut);}//线程在条件变量处等待
bool isqueueempty(){return _queue.empty();}//判断队列是否为空

void push(const T& in)
{
    LockReady lr(&_mut);//加锁
    _queue.push(in);//把对象放进队列
    pthread_cond_signal(&_cond);//唤醒在条件变量处阻塞的线程
}

T pop()
{
    T t=_queue.front();//取队列头的对象--拷贝构造
    _queue.pop();
    return t;
}

~threadPool()
{
    pthread_cond_destroy(&_cond);//销毁条件变量
    pthread_mutex_destroy(&_mut);//销毁锁
    for(const auto& thr :_threads)
    {
        delete thr;//销毁线程对象
    }
}

pthread_mutex_t *Mutex(){return &_mut;}//供static函数调用

void run()//遍历数组中的线程，逐个完成创建
{
    for(const auto& th:_threads)
    {
        threadData<T>*td=new threadData<T>(this,th->threadname());
//第一个参数是指向threadPool的指针，第二个是在thread类中调用的拿取线程名的函数
        th->start(handlertask,td);//第一个传需要调用的函数（任务），第二个传指向threadData对象的指针
     }
}

static threadPool<T>*getthpptr()
{
    if(nullptr==tp)
    {
        _Clock.lock();//加锁，指向threadpool的指针只有一个且线程都能访问，因此需要用锁来维护，这里是用的C++的锁
        if(nullptr==tp)
        {
            tp=new threadPool<T>();
        }
        _Clock.unlock();//解锁
    }
return tp;
}

private:
int _num;//用来标记线程名
pthread_mutex_t _mut;//锁
pthread_cond_t _cond;//条件变量
vector<thread*> _threads;//存储线程的数组
queue<T> _queue;//存放计算任务的队列

static threadPool<T>* tp;//类内声明
static std::mutex _Clock;//C++中的锁-类内声明
};
template<class T>
threadPool<T>* threadPool<T>::tp=nullptr;//类外定义
template<class T>
std::mutex threadPool<T>::_Clock;//类外定义
